package com.gbase8c.dmt.db.opengauss;

import com.gbase8c.dmt.db.object.TriggerObject;
import com.gbase8c.dmt.model.migration.dto.DataSourceDto;
import com.gbase8c.dmt.model.migration.dto.TriggerDto;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class TriggerObjectImpl extends MetaImpl implements TriggerObject {

    public TriggerObjectImpl(DataSourceDto dataSourceDto) {
        super(dataSourceDto);
    }

    @Override
    public List<String> getNames(Map<String, Object> params) {
        List<String> names = Lists.newArrayList();
        return names;
    }

    @Override
    public TriggerDto get(String name, Map<String, Object> params) {
        return null;
    }

    @Override
    public TriggerDto convert(TriggerDto triggerDto, Map<String, Object> params) {
        Boolean convertible = Boolean.TRUE;
        String srcTriggerBody = triggerDto.getSrcTriggerBody();
        String tarTriggerBody = srcTriggerBody.replaceAll(":NEW.","NEW.");
        if (!tarTriggerBody.contains("begin") && !tarTriggerBody.contains("BEGIN")) {
            tarTriggerBody = " BEGIN " + tarTriggerBody + " ;END";
        }
        triggerDto.setTarTriggerBody(tarTriggerBody);

        //字符串匹配declare...;
        List<String> declareVarList = Lists.newArrayList();
        String reg = "declare.*?;";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(triggerDto.getTarTriggerBody());
        int matcher_start = 0;
        while (matcher.find(matcher_start)){
            declareVarList.add(matcher.group());
            matcher_start = matcher.end();
        }

        String sb = matcher.replaceAll("").trim();
        String s1 = String.join("\r\n",declareVarList);
        String result = s1 + sb;

        //
        String s = result;
        String s2 = result;
        if (!result.contains("return new")) {
            Pattern pattern1 = Pattern.compile("[E,e][N,n][D,d]");
            Matcher matcher1 = pattern1.matcher(result);
            int matcher_start1 = 0;
            while (matcher1.find()){
//                System.out.println(matcher1.group());
                matcher_start1 = matcher1.start();
            }
//            System.out.println(s);
            s = result.substring(0,matcher_start1);
            s2 = s + " return new; \n END ;";
        }
        triggerDto.setTarTriggerBody(s2);
        triggerDto.setConvertible(convertible);
        if (triggerDto.getConvertible()){
            triggerDto.setConvertMsg("已完成");
        } else {
            triggerDto.setConvertMsg("失败");
        }

        return triggerDto;
    }

    @Override
    public String sql(TriggerDto triggerDto, Map<String, Object> params) {
        String triggerName = triggerDto.getName();
        String tarSchema = triggerDto.getTarSchema();
        String schema = triggerDto.getSchema();
        List<String> sqls = Lists.newArrayList();

        //创建触发器函数
        //create synonym t_class for test_dmt.t_class
        StringBuilder funcSb = new StringBuilder();
        StringBuilder triggerSb = new StringBuilder();
        String funcName = triggerDto.getName() + "_func";

        boolean preserveCase = triggerDto.getTask().getMigrateConfig().isPreserveCase();

        String tarTriggerBody = triggerDto.getTarTriggerBody();
        funcSb.append("create or replace function ").append(wrap(tarSchema,true)).append(".").append(funcName).append("()")
                .append(" returns trigger as $$ ").append(tarTriggerBody).append("$$ language plpgsql; \n");
        sqls.add(funcSb.toString());

        //创建触发器
        String timing = triggerDto.getActionTiming();
        String orientation = triggerDto.getActionOrientation();
        triggerSb.append("create trigger ").append(wrap(triggerName,preserveCase)).append(" ").append(timing).append(" ").append(triggerDto.getTriggeringEvent())
                .append(" on ").append(wrap(triggerDto.getEventObjectSchema(),true)).append(".").append(wrap(triggerDto.getEventObjectTable(),preserveCase))
                .append(" for each ").append(orientation).append(" execute procedure ").append(wrap(schema,true)).append(".").append(funcName).append("()");
        sqls.add(triggerSb.toString());
        log.info(sqls.toString());
        return sqls.toString();
    }

    @Override
    public TriggerDto getTriggerDto(String schema, TriggerDto triggerDto) {
        String sql = "select trigger_schema as schemaName,TRIGGER_NAME as triggerName, EVENT_OBJECT_SCHEMA  as eventObjectSchema,EVENT_OBJECT_TABLE  as eventObjectTable,\n" +
                "ACTION_STATEMENT as srcTriggerBody,ACTION_ORIENTATION  as actionOrientation,action_timing as actionTiming" +
                " from information_schema.triggers where TRIGGER_SCHEMA = ? and trigger_name = ?";
        TriggerDto dto = new TriggerDto();
        dto = query(sql.toString(),new BeanHandler<>(TriggerDto.class),schema,triggerDto.getName());
        return dto;
    }

    @Override
    public List<String> triggerSql(TriggerDto triggerDto) {
        String triggerName = triggerDto.getName();
        String tarSchema = triggerDto.getTarSchema();
        String schema = triggerDto.getTarSchema();
        List<String> sqls = Lists.newArrayList();

        //创建触发器函数
        StringBuilder funcSb = new StringBuilder();
        StringBuilder triggerSb = new StringBuilder();
        String funcName = triggerDto.getTarName() + "_func";

        boolean preserveCase = triggerDto.getTask().getMigrateConfig().isPreserveCase();

        String tarTriggerBody = triggerDto.getTarTriggerBody();
        funcSb.append("create or replace function ").append(wrap(tarSchema,preserveCase)).append(".").append(funcName).append("()")
                .append(" returns trigger as $$ ").append(tarTriggerBody).append("$$ language plpgsql; \n");
        sqls.add(funcSb.toString());

        //创建触发器
        String timing = triggerDto.getActionTiming();
        String orientation = triggerDto.getActionOrientation();
        triggerSb.append("create trigger ").append(wrap(triggerName,preserveCase)).append(" ").append(timing).append(" ").append(triggerDto.getTriggeringEvent())
                .append(" on ").append(wrap(triggerDto.getEventObjectSchema(),preserveCase)).append(".").append(wrap(triggerDto.getEventObjectTable(),preserveCase))
                .append(" for each ").append(orientation).append(" execute procedure ").append(wrap(schema,preserveCase)).append(".").append(funcName).append("()");
        sqls.add(triggerSb.toString());
        log.info(sqls.toString());
        return sqls;
    }

}
